package cn.xiaolang.function.java_gc;

import cn.xiaolang.common.utils.Monitor;
import lombok.extern.slf4j.Slf4j;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.concurrent.TimeUnit;

/**
 * 一 对象引用之-软引用
 * 如果对象只具有软引用，则
 * <p>
 * 内存空间充足时，垃圾回收器不会回收
 * 内存空间不足时，就会尝试回收这些对象。只要垃圾回收器没有回收它，该对象就可以被程序使用
 * <p>
 * 注意：
 * <p>
 * 软引用对象是在JVM内存不够的时候才会被回收，我们调用System.gc()方法只是起通知作用，JVM什么时候扫描回收对象是JVM自己的状态决定的。
 * 就算扫描到软引用对象真正开始GC也不一定会回收它，只有内存不够的时候才会回收。
 * 软引用对象回收规则适应的前提条件是这个对象只有软引用。所以在上面的用例中要把强引用清除。
 *
 * @author fuhw/Dean
 * @date 2020-05-14
 */
@Slf4j
public class SoftReferenceStarted {


    public static void main(String[] args) throws InterruptedException {
        softReferenceStart();
    }

    private static void softReferenceStart() throws InterruptedException {
        System.gc();
        TimeUnit.SECONDS.sleep(3);

        Monitor.printlnMemory("1.原可用内存和总内存");
        // 强引用
        byte[] object = new byte[10 * Monitor.MB];
        Monitor.printlnMemory("2.实例化10M的数组后");
        // 建立软引用
        ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
        SoftReference<Object> softReference = new SoftReference<>(object, referenceQueue);
        Monitor.printlnMemory("3.建立软引用,可以通过get()方法获取到关联对象");
        System.out.println("softReference : " + softReference);
        System.out.println("softReference.get() : " + softReference.get());
        System.out.println("referenceQueue.poll() : " + referenceQueue.poll());

        // 断开object的强引用
        object = null;
        Monitor.printlnMemory("4.执行object=null;断开强引用后");

        // Notify GC
        System.gc();
        TimeUnit.SECONDS.sleep(3);

        Monitor.printlnMemory("5.GC后,未回收object[]对象<===>");
        //第一次Full GC仅仅将虚引用加入到referenceQueue中，并未真实回收object[]对象
        System.out.println("softReference : " + softReference);
        System.out.println("softReference.get() : " + softReference.get());
        System.out.println("referenceQueue.poll() : " + referenceQueue.poll());

        System.gc();
        //显示softReference = null;或者 softReference.clear();断开软引用,关联对象变为不可达。可直接回收object[]对象
        Monitor.printlnMemory("6.再次GC后,内存空间不足时才会尝试回收object[]对象");
        System.out.println("softReference : " + softReference);
        System.out.println("softReference.get(): " + softReference.get());
        System.out.println("referenceQueue.poll() : " + referenceQueue.poll());

    }

}
